package com.xucia.jsonpath;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.mozilla.javascript.NativeArray;

import com.xucia.jsponic.data.Persistable;

public class JSONPath {
	public JSONPath() {
	}
	String resultType = "VALUE";
	Object[] result;
	public void trace(String expr, Object value, String path) {
//		if (expr.length() > 0)
	//	{
            List<String> xs = Arrays.asList(expr.split(";")); 
            String loc;
            boolean first = true;
            String x = "";
            for (String part : xs) {
            	if (first) {
            		loc = part;
            		first = false;
            	}
            	else
            		x += ";" + part;
            }
            	
            x = x.substring(1);
            Persistable val = (Persistable) value;
            if (val.has(loc))
               trace(x, val.get(loc), path + ";" + loc);
            else if ("*".equals(loc))
               walk(loc, x, val, path, new Walker() {
            	   public void walk(Object m,String l,String x,Persistable v,String p) {
            		   trace(m+";"+x,v,p);
            	   }
               });
            else if ("..".equals(loc)) {
               trace(x, val, path);
               walk(loc, x, val, path, new Walker() {
            	   public void walk(Object m,String l,String x,Persistable v,String p) {
            		   Object next = (m instanceof String ? v.get((String)m) : v.get((Integer)m,v));
            		   if (next instanceof Persistable)
            			   	trace("..;"+x,next,p+";"+m); 
            	   }
               });
            }
            else if (loc.matches(",")) { // [name1,name2,...]
            	String[] s=loc.split("'?,'?");
            	int n=s.length;
               for (int i=0; i<n; i++)
                  trace(s[i]+";"+x, val, path);
            }
            else if (loc.matches("^\\(.*?\\)$")) // [(expr)]
               trace(eval(loc, val, path.substring(path.lastIndexOf(";")+1))+";"+x, val, path);
            else if (loc.matches("^\\?\\(.*?\\)$")) // [?(expr)]
               walk(loc, x, val, path,new Walker() {
            	   public void walk(Object m,String l,String x,Persistable v,String p) {
            		   if (eval(l.replace("^\\?\\((.*?)\\)$","$1"),v[m],m)) 
            			   trace(m+";"+x,v,p);
        		   }
               });
            		   
            		   
            		   
            else if (loc.matches("^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$")) // [start:end:step]  phyton slice syntax
               slice(loc, x, val, path);
         //}
         //else
            //store(path, val);
      }

	
	
	String normalize(String expr) {
	         List subx = new ArrayList();
	         return expr.replaceAll("[\\['](\\??\\(.*?\\))[\\]']","")//, function($0,$1){return "[#"+(subx.push($1)-1)+"]";})
	                    .replaceAll("'?\\.'?|\\['?", ";")
	                    .replaceAll(";;;|;;", ";..;")
	                    .replaceAll(";$|'?\\]|'$", "")
	                    .replaceAll("#([0-9]+)","");//, function($0,$1){return subx[$1];});
	      }
	
	String asPath(String path) {
	         String[] x = path.split(";");
	         String p = "$";
	         for (int i=1,n=x.length; i<n; i++)
	            p += x[i].matches("^[0-9*]+$") ? ("["+x[i]+"]") : ("['"+x[i]+"']");
	         return p;
	      }
	boolean store(String p, String v) {
	         if (p.length() > 0) result[result.length] = resultType == "PATH" ? asPath(p) : v;
	         return p.length() > 0;
	      }
	      Object walk(String loc, String expr, Object val, String path, Walker f) {
	         if (val instanceof NativeArray) {
	        	 int n=((NativeArray) val).length();
	            for (int i=0; i<n; i++)
	                  f.walk(i,loc,expr,val,path);
	         }
	         else if (val instanceof Persistable) {
	        	 for (((Persistable)val).keys)
	                  f.walk(m,loc,expr,val,path);
	         }
	      }
	      interface Walker {
	    	  void walk(Object m, String loc, String expr, Persistable val, String path);
	      }
	      void slice(String loc, String expr, NativeArray val, String path) {
	            int len=val.length(), start=0, end=len, step=1;
	            //loc.replaceAll("^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$", function($0,$1,$2,$3){start=parseInt($1||start);end=parseInt($2||end);step=parseInt($3||step);});
	            start = (start < 0) ? Math.max(0,start+len) : Math.min(len,start);
	            end   = (end < 0)   ? Math.max(0,end+len)   : Math.min(len,end);
	            for (int i=start; i<end; i+=step)
	               trace(i+";"+expr, val, path);
	      }
	      public Object eval(String x,Object  _v, String _vname) {
	    	 return null; 
	      }
	      public Object execute(Object obj, String expr) {
	   Object root = obj;
	   if (expr.length() > 0  && (resultType == "VALUE" || resultType == "PATH")) {
	      trace(normalize(expr).replace("^\\$;/",""), obj, "$");
	      return result.length > 0 ? result : false;
	   }
	} 

}
